﻿using Haidou.Wpf.UI.Util;
using Haidou.Wpf.UI.ViewModel;
using Haidou.Wpf.Util;
using Haidou.Wpf.Util.InterProcessChannel;
using Haidou.Wpf.Util.Settings;
using Microsoft.VisualBasic.ApplicationServices;
using Microsoft.Win32;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Navigation;
using Application = System.Windows.Application;
using StartupEventArgs = System.Windows.StartupEventArgs;
using UnhandledExceptionEventArgs = System.UnhandledExceptionEventArgs;

namespace Haidou.Wpf.UI
{
	/// <summary>
	/// Interaction logic for App.xaml
	/// </summary>
	public partial class App  : IDisposable
	{


		#region Properties

		public static HandyControl.Controls.NotifyIcon NotifyIcon { get; private set; }

		public static ViewModelLocator? Instance;



		/// <summary>
		/// UI的Commands  ---命令
		/// </summary>
		public static ApplicationViewModel MainViewModel { get; private set; }

		private static Mutex _mutex;

		private static bool _accepted;
		private readonly List<Exception> _exceptionList = new();

		private readonly object _lock = new();

		private static StartupEventArgs _args;
		public static StartupEventArgs Args
		{
			get => _args;
			set
			{
				_args = value;
			
				//CheckAdmin(Args);
				if (!App_Startup.DisplayApp(Args))
				{
					System.Windows.Application.Current.Shutdown();
					return;
				}
			}
		}


		#endregion


		public void Dispose()
		{

			if (_mutex != null && _accepted)
			{
				_mutex.ReleaseMutex();
				_accepted = false;
			}

			_mutex?.Dispose();
		}

		private void Application_Startup(object sender, StartupEventArgs e)
		{
			try
			{
				//应用进程
				Arguments.Is64BitProcess = Environment.Is64BitProcess;

				//Unhandled Exceptions.未处理的异常。
				AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;



				///尝试切换到新主题
				//ThemeHelper.SelectTheme(UserSettings.All.MainTheme);



				// 主题的变化。
				SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;


				#region Download mode

				if (Arguments.IsInDownloadMode)
				{
					//Downloader downloader = new()
					//{
					//	DownloadMode = Arguments.DownloadMode,
					//	DestinationPath = Arguments.DownloadPath
					//};
					//downloader.ShowDialog();

					Environment.Exit(90);
					return;
				}

				#endregion


				#region Settings persistence mode 持久模式

				if (Arguments.IsInSettingsMode)
				{
					//SettingsPersistenceChannel.RegisterServer();
					return;
				}

				#endregion


				#region If set, it allows only one instance per user   如果设置，它只允许每个用户有一个实例

				//singleton 基于每个用户和每个可执行文件的模式工作。
				//这意味着不同的用户和/或不同的可执行实例可以共存。
				//部分代码在调试模式下无法工作，因为SetForegroundWindow()需要关注调用该方法的前台窗口。
				if (UserSettings.All.SingleInstance && !Arguments.NewInstance)
				{
					try
					{
						using (Process thisProcess = Process.GetCurrentProcess())
						{
							System.Security.Principal.SecurityIdentifier? user = System.Security.Principal.WindowsIdentity.GetCurrent().User;
							string name = thisProcess.MainModule?.FileName ?? Assembly.GetEntryAssembly()?.Location ?? "海豆Desktop";
							string location = Convert.ToBase64String(Encoding.UTF8.GetBytes(name));
							string mutexName = (user?.Value ?? Environment.UserName) + "_" + location;

							_mutex = new Mutex(true, mutexName, out _accepted);


							//如果mutext未能被接受，这意味着另一个进程已经打开了它。
							if (!_accepted)
							{

								//切换到另一个应用程序(如果有多个应用程序，只使用一个)。使用程序集的名称。
								using (Process? process = Process.GetProcessesByName(thisProcess.ProcessName).FirstOrDefault(f => f.MainWindowHandle != thisProcess.MainWindowHandle))
								{
									if (process != null)
									{
										//List<IntPtr> handles = GetWindowHandlesFromProcess(process);


										////设置焦点前显示窗口。
										//User32.ShowWindow(handles.Count > 0 ? handles[0] : process.Handle, ShowWindowCommands.ShowNoActivate);

										////为用户设置窗口焦点。
										//User32.SetForegroundWindow(handles.Count > 0 ? handles[0] : process.Handle);

										InstanceSwitcherChannel.SendMessage(process.Id, e.Args);

										Environment.Exit(0);

									}
									else
									{

										//NET 6之后因为性能机制优化，窗口关闭会直接回收，线程不存在该窗口，这里不能重新创建了new 了因为已经是一个新的进程 
										//再上面找不到窗口的情况下，这里只能置顶 

										//ThreadExitis("海豆Desktop");
										//returnhWnd("海豆Desktop");


										IntPtr hWnd = Win32.FindWindow(null, "我的鼠标");
										IntPtr hWnd1 = Win32.FindWindow(null, "我的AI设备");

										if (hWnd != IntPtr.Zero)
										{
											// 找到了窗口句柄
											// 现在您可以使用 SetForegroundWindow 来置顶窗口

											ShowWindowAsync(hWnd, WS_SHOWNORMAL);
											SetForegroundWindow(hWnd);


										}
										else if (hWnd1 != IntPtr.Zero)
										{
											// 找到了窗口句柄
											// 现在您可以使用 SetForegroundWindow 来置顶窗口

											ShowWindowAsync(hWnd1, WS_SHOWNORMAL);
											SetForegroundWindow(hWnd1);
										}


									}


									//如果没有可用的窗口(应用程序在系统托盘中)，显示一个警告。
									//if (warning)
									//	Dialog.Ok(LocalizationHelper.Get("S.Warning.Single.Title"), LocalizationHelper.Get("S.Warning.Single.Header"), LocalizationHelper.Get("S.Warning.Single.Message"), Icons.Info);

									return;
								}
							}

							//如果这是第一个实例，请注册进程间通道来监听其他实例。
							InstanceSwitcherChannel.RegisterServer(InstanceSwitch_Received);
						}
					}
					catch (Exception ex)
					{
						LogWriter.Log(ex, "Impossible to check if another instance is running.|无法检查另一个实例是否正在运行");
					}
				}

				#endregion

				//WPF系统级 渲染模式。 SoftwareOnly 仅软件
				RenderOptions.ProcessRenderMode = UserSettings.All.DisableHardwareAcceleration ? RenderMode.SoftwareOnly : RenderMode.Default;


				///为调度程序设置工作区
				SetWorkaroundForDispatcher();


				#region Tray icon and view model

			

				MainViewModel = (ApplicationViewModel)FindResource("AppViewModel") ?? new ApplicationViewModel();

			


				#endregion

				#region Tasks

				Task task = Task.Run(() =>
				{

					Global.StartupDateTime = DateTime.Now;



					Arguments.SystemTypeDetails = Global.SystemTypeDetails;

					///系统的
					Arguments.Is64BitOperatingSystem = Environment.Is64BitOperatingSystem;





					//系统名称
					//SystemDetection.OSystemName;

					//LogWriter.Log($"启动了应用,启动时间：" + Global.StartupDateTime + "    系统名称：" + SystemDetection.OSystemName + $"|{Global.SystemTypeDetails}");


					//增加工具提示显示的持续时间。 它提供了一种在用户将鼠标悬停在一个元素上时显示临时信息（工具提示）的功能
					ToolTipService.ShowDurationProperty.OverrideMetadata(typeof(DependencyObject), new FrameworkPropertyMetadata(int.MaxValue));

					//设置安全协议
					SetSecurityProtocol();

					//解析参数。
					Arguments.Prepare(e.Args);

					//语言
					LocalizationHelper.SelectCulture(UserSettings.All.LanguageCode);

					//注册 快捷键
					//RegisterShortcuts();


					//注册桌面快捷方式图标
					App_Startup.UpdateShortcutIco();



					App_Startup.SetMeAutoStart(true);

					//保存本地配置项   AI键语音输入 默认开启
					UserSettings.All.Automaticinputornot = true;
					UserSettings.Save();

					//bool Network = NetworkDetectionHelper.LocalConnectionStatus();
					//if (!Network)
					//{
					//	LogWriter.Log("Error", "网络连接不可用，请检查本机是否联网!!");
					//	Arguments.NetworkStatus = Network;

					//}


					//保存本地配置项
					UserSettings.All.CurrentProcessId = 0;
					UserSettings.Save();



				});

				Task.Factory.StartNew(MainViewModel.ClearTemporaryFiles, TaskCreationOptions.LongRunning);//连续运行 指定任务将是长时间运行的粗粒度操作，涉及
				Task.Factory.StartNew(async () => await MainViewModel.CheckForUpdates(), TaskCreationOptions.LongRunning);//检查更新
				Task.Factory.StartNew(MainViewModel.SendFeedback, TaskCreationOptions.LongRunning);


				#endregion




				#region Startup

				//WorkingWithWebView2Permissions();

				//App_Startup.InitChrome();

				//InitialResourceDictionary();

				SetWindowDefaultStyle();
				SetNavigationWindowDefaultStyle();





				MainViewModel.Open.Execute(UserSettings.All.StartUp);

				#endregion

			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "应用启动的时候 发生了异常. App.Application_Startup");

			}
		}

		private void Application_Exit(object sender, ExitEventArgs e)
		{
			SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged;

			try
			{
				//Haidou.Wpf.UI.Windows.Other.Startup.StopDevice();
				MutexList.RemoveAll();
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Impossible to remove all mutexes of the opened projects.||无法删除所有已打开项目的互斥体");
			}

			try
			{
				NotifyIcon?.Dispose();
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Impossible to dispose the system tray icon.||无法处理系统托盘图标");
			}

			try
			{
				//EncodingManager.StopAllEncodings();
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Impossible to cancel all encodings.||无法取消所有编码");
			}

			try
			{
				//SettingsExtension.ForceSave();
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Impossible to save the user settings.||无法保存用户设置");
			}

			try
			{
				if (_mutex != null && _accepted)
				{
					_mutex.ReleaseMutex();
					_accepted = false;
				}
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Impossible to release the single instance mutex.||无法释放单实例互斥体");
			}

			try
			{
				//HotKeyCollection.Default.Dispose();
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Impossible to dispose the hotkeys.||无法处理热键");
			}


		}

		private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
		{
			LogWriter.Log(e.Exception, "On dispacher unhandled exception - Unknown.|调度程序上未处理的异常-未知");
			LogWriter.Log(e.Exception.Message, "On dispacher unhandled exception - Unknown.|调度程序上未处理的异常-未知");

			try
			{


				// 关闭当前进程
				System.Diagnostics.Process.GetCurrentProcess().Kill();
				//ShowException(e.Exception);
				//Global.CloseAINavigate();

			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Error while displaying the error.显示错误时出错。");
				//Ignored.
			}
			finally
			{
				//e.Handled = true;
			}

		}


		private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
		{
			if (e.ExceptionObject is not Exception exception)
			{
				return;
			}

			LogWriter.Log(exception, "Current domain unhandled exception - Unknown|当前域未处理的异常-未知");
			//Global.CloseAINavigate();

			try
			{
				//ShowException(exception);
				//Global.CloseAINavigate();

				// 关闭当前进程
				System.Diagnostics.Process.GetCurrentProcess().Kill();
				//ShowException(exception);
			}
			catch (Exception)
			{
				//Ignored.忽略。
			}
		}

		/// <summary>
		/// 实例切换_已接收  切换打开的窗口
		/// </summary>
		/// <param name="_"></param>
		/// <param name="message"></param>
		internal static void InstanceSwitch_Received(object _, InstanceSwitcherMessage message)
		{
			try
			{
				string[] args = message.Args;

				if (args?.Length > 0)
				{
					Arguments.Prepare(args);
				}

				if (Arguments.Open)
				{
					MainViewModel.Open.Execute(Arguments.WindownToOpen, true);
				}
				else
				{
					MainViewModel.Open.Execute(UserSettings.All.StartUp);
				}
			}
			catch (Exception e)
			{
				LogWriter.Log(e, "Unable to execute arguments from IPC.|无法从IPC执行参数");
			}
		}

		/// <summary>
		/// 设置安全协议
		/// </summary>
		private static void SetSecurityProtocol()
		{
			try
			{
				ServicePointManager.Expect100Continue = true;
				ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "无法设置网络属性.SetSecurityProtocol");//无法设置网络属性
			}
		}

		/// <summary>
		/// 为调度程序设置工作区
		/// </summary>
		private static void SetWorkaroundForDispatcher()
		{
			try
			{
				//定义调度程序在请求处理时如何对遇到的故障做出反应。定义调度程序如何对失败做出反应的值

				//重置调度程序的状态，以便在下次需要请求时尝试另一个请求。
				//虽然此选项有时可以“修复”无响应性，但它不支持
				//通常的处理时间，这可能至关重要。选择此选项会导致
				//到意外的行为。
				if (UserSettings.All.WorkaroundQuota)
				{
					BaseCompatibilityPreferences.HandleDispatcherRequestProcessingFailure = BaseCompatibilityPreferences.HandleDispatcherRequestProcessingFailureOptions.Reset;
				}

#if DEBUG
				///提供专门针对Windows演示的调试跟踪支持
				PresentationTraceSources.DataBindingSource.Listeners.Add(new ConsoleTraceListener());
				PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Warning;

				//定义调度程序在请求处理时如何对遇到的故障做出反应。

				//HandleDispatcherRequestProcessingFailureOptions.Throw
				//抛出异常。这个选项立即给应用程序带来了问题
				//开发者注意。定义调度程序在请求处理时如何应对遇到的故障。
				BaseCompatibilityPreferences.HandleDispatcherRequestProcessingFailure = BaseCompatibilityPreferences.HandleDispatcherRequestProcessingFailureOptions.Throw;

#endif
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Impossible to set the workaround for the quota crash.|无法设置配额崩溃的解决方法");
			}


		}

		/// <summary>
		/// 系统事件_用户首选项已更改
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private static void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
		{
			try
			{


				if (e.Category != UserPreferenceCategory.General)
				{
					return;
				}

				//ThemeHelper.SelectTheme(UserSettings.All.MainTheme);

				//if (UserSettings.All.GridColorsFollowSystem)
				//{
				//	bool isSystemUsingDark = ThemeHelper.IsSystemUsingDarkTheme();
				//	UserSettings.All.GridColor1 = isSystemUsingDark ? Constants.DarkEven : Constants.VeryLightEven;
				//	UserSettings.All.GridColor2 = isSystemUsingDark ? Constants.DarkOdd : Constants.VeryLightOdd;
				//}
			}
			catch (Exception ex)
			{

				LogWriter.Log(ex, "SystemEvents_UserPreferenceChanged");

			}
		}





		/// <summary>
		/// 设置窗口默认样式
		/// </summary>
		/// <param name="resourceKey"></param>
		public void SetWindowDefaultStyle(object resourceKey = null)
		{
			try
			{


				FrameworkPropertyMetadata metadata = resourceKey == null
					? new FrameworkPropertyMetadata(Application.Current.FindResource(typeof(Window)))
					: new FrameworkPropertyMetadata(Application.Current.FindResource(resourceKey));

				FrameworkElement.StyleProperty.OverrideMetadata(typeof(Window), metadata);
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "App.SetWindowDefaultStyle");

			}
		}

		public void SetNavigationWindowDefaultStyle(object resourceKey = null)
		{
			try
			{


				FrameworkPropertyMetadata metadata = resourceKey == null
					? new FrameworkPropertyMetadata(Application.Current.FindResource(typeof(NavigationWindow)))
					: new FrameworkPropertyMetadata(Application.Current.FindResource(resourceKey));

				FrameworkElement.StyleProperty.OverrideMetadata(typeof(NavigationWindow), metadata);

			}
			catch (Exception ex)
			{

				LogWriter.Log(ex, "App.SetNavigationWindowDefaultStyle");

			}
		}





		private const int WS_SHOWNORMAL = 1;
		// 设置窗口的显示状态，而无需等待操作完成。
		[DllImport("user32.dll")]
		private static extern bool ShowWindowAsync(IntPtr hwnd, int cmdShow);
		// 将创建指定窗口的线程引入前台并激活窗口。 键盘输入将定向到窗口，
		// 并为用户更改各种视觉提示。 系统为创建前台窗口的线程分配的优先级略高于其他线程。
		[DllImport("user32.dll")]
		private static extern bool SetForegroundWindow(IntPtr hwnd);

		private static Process GetRunningInstance()
		{
			Process pCurrent = Process.GetCurrentProcess();
			Process[] processes = Process.GetProcessesByName(pCurrent.ProcessName);
			foreach (Process p in processes)
			{
				if (p.Id != pCurrent.Id)
				{
					string filename = Assembly.GetExecutingAssembly().Location.Replace("dll", "exe");
					if (filename == pCurrent.MainModule.FileName)
					{
						return p;
					}
				}
			}
			return null;
		}

		private static void HandleRunningInstance(Process instance)
		{
			ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
			SetForegroundWindow(instance.MainWindowHandle);
		}





	}

}
